/**
Player.cpp
A class to control the player in A Man of Maps
*/

#include "Player.h"

Player::Player(b2World* world, int ent_type, sf::Vector2f pos, std::string file, float scale, float rotation){

    type = ent_type;
    position = pos;
    angle = rotation;
    image = true;
    eScale = scale;
    currentMap = 3;     //why 3? 10/16/14

    //Player stats
    maxEnergy = 150;
    energy = maxEnergy;
    maxSupplies = 100;
    supplies = maxSupplies;


    playerWidth = 100;  //x ooordinate of the texture rect of the player, in px
    playerHeight = 200; //y ooordinate of the texture rect of the player, in px
    playerDensity = 5.0;    //player density for physics fixture
    playerFriction = 0;   //player friction for physics fixture, also affects animation
    playerLinearDamping = 0;  //player linear damping for movement
    playerAnimationDamping = 500;  //animation lag. Larger numbers, bigger lag
    playerVelocityRate = 3.0;
    playerFrameRate = 100;

    texture.loadFromFile(file);
    Init(world);
    setTxRect(sf::IntRect(0,0,playerWidth,playerHeight));
    body->SetFixedRotation(true);
    body->GetFixtureList()->SetFriction(playerFriction);
    body->GetFixtureList()->SetDensity(playerDensity);
    body->SetLinearDamping(playerLinearDamping);
    body->GetFixtureList()->SetRestitution(0);
    std::cout << "Friction set : " << body->GetFixtureList()->GetFriction() << std::endl;
    std::cout << "Density set : " << body->GetFixtureList()->GetDensity() << std::endl;
    std::cout << "Damping set : " << body->GetLinearDamping() << std::endl;

    //visionCircle
    visionCircle.setFillColor(sf::Color::Transparent);
    visionCircle.setOutlineThickness(3);
    visionCircle.setOutlineColor(sf::Color::Green);
    visionCircle.setRadius(100);
}

void Player::Update(){
    //update the animation
    if(animated){
        //std::cout << "Animated" << std::endl;
        eAnimation.Update(eclock);
        int frame = eAnimation.getCurrentFrame();
        textureRect.left = (frame * textureRect.width);
        rect.setTextureRect(textureRect);
    }

    /*
    if(body->IsAwake()){
        std::cout << "Vx: " << body->GetLinearVelocity().x <<  " Vy: " << body->GetLinearVelocity().y << std::endl;
    }
    */

    //Set the frame rate proportional to the velocity
    if (isMoving()){
        setFrameRate(100);
    }else{
        setFrameRate(0);
        setCurrentFrame(0);
    }


    //compute the player direction based on velocity and update the rect image
    if(body->GetLinearVelocity().x != 0 || body->GetLinearVelocity().y  != 0){
        direction = atan2(body->GetLinearVelocity().y * -1, body->GetLinearVelocity().x) * 180 / PI;
        //std::cout << "Direction: " << direction << std::endl;
        setFacingImage();
    }

    //set the screen position and angle of the player rect based on the physics body
    rect.setPosition(body->GetPosition().x * SCALE, body->GetPosition().y * SCALE);
    rect.setRotation(180/b2_pi * body->GetAngle());

    //set the location of the vision circle
    visionCircle.setPosition(sf::Vector2f(rect.getPosition().x - visionCircle.getRadius(),
                                           rect.getPosition().y - visionCircle.getRadius()));

}

Player::~Player()
{
    //dtor
}

// Set the direction of the player and change the facing rect
void Player::setFacingImage(){

    //DOWN
    if(direction <= -67.5 && direction >= -112.5){
        setTxRect(sf::IntRect(0,0,playerWidth,playerHeight));
    }

     //UP
    if(direction >= 67.5 && direction <= 112.5){
        setTxRect(sf::IntRect(0,playerHeight,playerWidth,playerHeight));
    }

    //RIGHT
    if(direction <= 22.5 && direction >= -22.5){
        setTxRect(sf::IntRect(0,playerHeight *2 ,playerWidth,playerHeight));
    }

    //LEFT
    if((direction >= 157.5 && direction <= 180) || (direction <= -157.5 && direction >= -180.0) ){
        setTxRect(sf::IntRect(0,playerHeight *3 ,playerWidth,playerHeight));
    }

    //DOWN RIGHT
    if(direction > -67.5 && direction < -22.5){
        setTxRect(sf::IntRect(0,playerHeight * 4,playerWidth,playerHeight));
    }

    //DOWN LEFT
    if(direction > -157.5 && direction < -112.5){
        setTxRect(sf::IntRect(0, playerHeight * 5,playerWidth,playerHeight));
    }

    //UP RIGHT
    if(direction < 67.5 && direction > 22.5){
        setTxRect(sf::IntRect(0, playerHeight * 6,playerWidth,playerHeight));
    }

    //UP LEFT
    if(direction < 157.5 && direction > 112.5){
        setTxRect(sf::IntRect(0, playerHeight * 7,playerWidth,playerHeight));
    }

}

// Render Method
void Player::Render(sf::RenderWindow& window ){

    //draw the object only if visible == true
    if(visible){
        window.draw(rect);
        //window.draw(visionCircle);      //draw the visionCircle
        sf::RectangleShape r2 = rect;
        r2.setFillColor(sf::Color::Transparent);
        r2.setOutlineColor(sf::Color::Red);
        r2.setOutlineThickness(1);
        window.draw(r2);
    }
}

//return the rect position of the player
sf::Vector2f Player::getPosition(){
    //std::cout << "Player Position: " << rect.getPosition().x << " " << rect.getPosition().y << std::endl;
    return rect.getPosition();

}

//returns the players circleshape
sf::CircleShape* Player::getVisionCircle(){
    return &visionCircle;
}

//returns the players circleshape
sf::RectangleShape Player::getRect(){
    return rect;
}

//returns the player speed
float Player::getVelocity(){
      return playerVelocityRate;
}

//returns the player speed
float Player::getCurrentSpeed(){
      return sqrt(body->GetLinearVelocity().x * body->GetLinearVelocity().x
        + body->GetLinearVelocity().y * body->GetLinearVelocity().y);
}

//sets the linear velocity of the player
void Player::setSpeed(b2Vec2 v){
    body->SetLinearVelocity(v);
}

//returns true if the player speed is greater than the friction
bool Player::isMoving(){
    if(getCurrentSpeed() > playerFriction){
        return true;
    }else return false;
}

//gets the map ID for the player
int Player::getMapIndex(){
    return currentMap;
}

//sets the map ID for the player
void Player::setCurrentMap(int mapID){
    currentMap = mapID;
}

//Return the distance moved (from saved 'Start' to current position)
float Player::getDistanceMoved(){

    if(isMoving()){
        return Utility::getDistance(start.x, start.y, getPosition().x, getPosition().y);
    }else return 0;

}

//Start moving the player in the supplied direction at the player's vel rate
//initialize the start position
void Player::startMoving(b2Vec2 dir){
    setSpeed(b2Vec2(dir.x * playerVelocityRate, dir.y * playerVelocityRate));
    start = getPosition();
}

//Stop moving the player
void Player::stopMoving(){
    setSpeed(b2Vec2(0,0));
}

void Player::setEnergy(int x){

    if(x > maxEnergy){
        energy = maxEnergy;
    }else energy = x;
    //std::cout << "Energy set: " <<  energy << std::endl;
}

void Player::setSupplies(int x){

    if(x > maxSupplies){
        supplies = maxSupplies;
    }else supplies = x;
    //std::cout << "Energy set: " <<  energy << std::endl;
}


int Player::getEnergy(){
    return energy;
}

int Player::getMaxEnergy(){
    return maxEnergy;
}

int Player::getSupplies(){
    return supplies;
}

int Player::getMaxSupplies(){
    return maxSupplies;
}

void Player::setPosition(sf::Vector2f v){
    body->SetTransform(b2Vec2(v.x / SCALE, v.y / SCALE), body->GetAngle());
    Update();
}
